﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

namespace UFrame
{
    /// <summary>
    /// 负责音效播放
    /// 1. 还原音效
    /// 2. 
    /// 
    /// </summary>
    public class AudioMa
    {
        private AudioMa()
        {
        }

        private static Dictionary<string, AudioClip> mClipDic = new Dictionary<string, AudioClip>();
        private static List<AudioData> mAudioDataList = new List<AudioData>();
        private static GameObject mAudioParent;

        private static Dictionary<EAudioType, AudioTypeConfig>
            configDic = new Dictionary<EAudioType, AudioTypeConfig>();

        public static Dictionary<string, AudioConfig> audioConfigDic = new Dictionary<string, AudioConfig>();

        public static int mCacheCount = 15;

        private static Dictionary<string, float> ignoreTime = new Dictionary<string, float>();

        public static string mSFX = "SFX";
        public static string mBGM = "BGM";
        public static string mTK = "TK";
        public static string mTheme = "Theme";

        private static bool isAudio = false;
        private static bool isMusic = false;

        public static bool IsAudio
        {
            set
            {
                isAudio = value;
                PlayerPrefs.SetInt("UFrameAudio", value ? 1 : 0);
            }
            get
            {
                int val = PlayerPrefs.GetInt("UFrameAudio", 1);

                return val > 0;
            }
        }

        public static bool IsMusic
        {
            set
            {
                isMusic = value;
                PlayerPrefs.SetInt("UFrameMusic", value ? 1 : 0);
            }
            get
            {
                int val = PlayerPrefs.GetInt("UFrameMusic", 1);
                return val > 0;
            }
        }

        public static void AddAudioConfig(AudioConfig a)
        {
            if (audioConfigDic.ContainsKey(a.fileName))
            {
                audioConfigDic[a.fileName] = a;
            }
            else
            {
                audioConfigDic.Add(a.fileName, a);
            }
        }

        public static AudioConfig GetAudioConfig(string fileName)
        {
            if (audioConfigDic.ContainsKey(fileName))
            {
                return audioConfigDic[fileName];
            }
            else
            {
                return null;
            }
        }

        public static void Init(List<string> pathList = null)
        {
            isAudio = PlayerPrefs.GetInt("UFrameAudio", 1) > 0;
            isMusic = PlayerPrefs.GetInt("UFrameMusic", 1) > 0;

            mClipDic.Clear();
            mAudioDataList.Clear();
            if (mAudioParent != null)
            {
                GameObject.DestroyImmediate(mAudioParent);
            }

            if (pathList != null)
            {
                for (int i = 0; i < pathList.Count; i++)
                {
                    AudioClip ac = ResourcesMa.Load<AudioClip>(pathList[i]);
                    string fileName = Path.GetFileNameWithoutExtension(pathList[i]);
                    mClipDic.Add(fileName, ac);
                }
            }

            mAudioParent = new GameObject();
            mAudioParent.gameObject.name = "AudioParent";
            GameObject.DontDestroyOnLoad(mAudioParent);
            InitConfig();

            //初始化配置文件
            for (int i = 0; i < mCacheCount; i++)
            {
                CreateAudioSource();
            }
        }

        private static void InitConfig()
        {
            configDic.Clear();
            configDic.Add(EAudioType.SFX, new AudioTypeConfig()
            {
                typeStartChar = mSFX,
                audioType = EAudioType.SFX,
                volume = 1,
            });
            configDic.Add(EAudioType.Theme, new AudioTypeConfig()
            {
                typeStartChar = mTheme,
                audioType = EAudioType.Theme,
                volume = 1,
            });
            configDic.Add(EAudioType.TK, new AudioTypeConfig()
            {
                typeStartChar = mTK,
                audioType = EAudioType.TK,
                volume = 1,
            });
            configDic.Add(EAudioType.BGM, new AudioTypeConfig()
            {
                typeStartChar = mBGM,
                audioType = EAudioType.BGM,
                volume = 1,
            });
        }


        public static void AddAudio(string path)
        {
            AudioClip ac = ResourcesMa.Load<AudioClip>(path);
            string fileName = Path.GetFileNameWithoutExtension(path);
            mClipDic.Add(fileName, ac);
        }

        [Obsolete("暂不支持这个")]
        public void PlayAudioQueue(string[] pathAry)
        {
            
        }

        public static void UpdateAudioState()
        {
            foreach (var item in mAudioDataList)
            {
                
            }

            if (ignoreTime.Count > 0)
            {
                foreach (var item in ignoreTime)
                {
                    
                }
            }

        }


        public static void PlayAudio(string path, bool isLoop = false, float delay = 0)
        {
            AudioData source = GetAudioComponent();
            source.loop = isLoop;
            AudioClip ac = null;
            string fileName = Path.GetFileNameWithoutExtension(path);
            if (mClipDic.ContainsKey(path))
            {
                ac = mClipDic[path];
            }
            else
            {
                ac = ResourcesMa.Load<AudioClip>(path);
            }

            if (ac == null)
            {
                PLDebug.LogError("没找到该音效: " + path);
                return;
            }

            Play(fileName, source, ac, isLoop, delay);
        }

        private static void Play(string fileName, AudioData source, AudioClip ac, bool isLoop = false, float delay = 0)
        {
            SetAudioType(fileName, source);

            if (audioConfigDic.ContainsKey(fileName))
            {
                var audioConfig = audioConfigDic[fileName];
                delay = audioConfig.delay;
                source.AS.loop = audioConfig.isLoop;
                source.AS.volume = audioConfig.volume;
                if (AudioAdvanced.IsIgnoreAudio(audioConfig, ignoreTime))            //忽略一些音效
                {
                    return;
                }

                AudioAdvanced.IsMuteAudio(audioConfig, mAudioDataList);            

                if (AudioAdvanced.IsNoMuteAudio(audioConfig, mAudioDataList))
                {
                    return;
                }
            }
            else
            {
                source.AS.volume = 1f;
                source.AS.loop = isLoop;
            }

            source.AS.clip = ac;
            
            if (delay <= 0)
            {
                if (isAudio){
                    source.AS.Play();
                }
            }
            else
            {
                CoroutineTool.I.StartCoroutine(OnDelayPlay(delay, source));
            }
        }

        public static void Play(AudioClip ac, bool isLoop = false, float delay = 0)
        {
            AudioData source = GetAudioComponent();
            string fileName = ac.name;
            Play(fileName, source, ac, isLoop, delay);
        }
        
        private static void SetAudioType(string fileName, AudioData source)
        {
            if (fileName.StartsWith(mSFX))
            {
                source.audioType = EAudioType.SFX;
            }
            else if (fileName.StartsWith(mBGM))
            {
                source.audioType = EAudioType.BGM;
            }
            else if (fileName.StartsWith(mTK))
            {
                source.audioType = EAudioType.TK;
            }
            else
            {
                source.audioType = EAudioType.Common;
            }
        }
        
        private static IEnumerator OnDelayPlay(float time, AudioData data)
        {
            yield return new WaitForSeconds(time);
            if (data.AS != null)
            {
                if (isAudio)
                    data.AS.Play();
            }
        }


        public static void StopAudio(EAudioType type)
        {
            for (int i = 0; i < mAudioDataList.Count; i++)
            {
                var data = mAudioDataList[i];
                if (type == EAudioType.All)
                {
                    data.AS.Stop();
                }
                else if (data.AS.isPlaying && data.audioType == type)
                {
                    data.AS.Stop();
                    break;
                }
            }
        }

        public static void StopAudio(string clipName)
        {
            string n = Path.GetFileName(clipName);
            for (int i = 0; i < mAudioDataList.Count; i++)
            {
                var a = mAudioDataList[i];
                if (a.AS.isPlaying && a.AS.clip.name == n)
                {
                    a.AS.Stop();
                    break;
                }
            }
        }

        public static void StopAudio()
        {
            for (int i = 0; i < mAudioDataList.Count; i++)
            {
                var a = mAudioDataList[i];
                a.AS.Stop();
            }
        }

        public static void RecoverAudio()
        {
            for (int i = 0; i < mAudioDataList.Count; i++)
            {
                var a = mAudioDataList[i];
                a.AS.Play();
            }
        }
        
        private static AudioData GetAudioComponent()
        {
            for (int i = 0; i < mAudioDataList.Count; i++)
            {
                var data = mAudioDataList[i];
                if (!data.AS.isPlaying && !data.loop)
                {
                    return data;
                }
            }

            return CreateAudioSource();
        }

        public static AudioData CreateAudioSource()
        {
            GameObject go = new GameObject();
            AudioSource audioSource = go.AddComponent<AudioSource>();
            go.name = "audio" + mAudioDataList.Count;
            go.transform.SetParent(mAudioParent.transform);
            AudioData result = new AudioData()
            {
                AS = audioSource
            };

            mAudioDataList.Add(result);

            return result;
        }
    }

    /// <summary>
    /// 音效整体配置
    /// </summary>
    public class AudioTypeConfig
    {
        public EAudioType audioType;
        public string typeStartChar;
        public float volume = 1;
    }

    public class AudioConfig
    {
        public string fileName;
        public string fileNameAry;
        public string type;
        public float volume;
        public bool isLoop;
        public float ignoreTime;
        public float delay;
        
        /// <summary>
        /// 如果正在播放这些音乐， 就不播放当前音乐
        /// </summary>
        public string mutexAudioNoPlay; //

        /// <summary>
        /// 如果正在播放这些音乐， 把他们暂停,播放当前音乐
        /// </summary>
        public string mutexAudioPlay; //如果正在播放这些音乐， 把他们暂停,播放当前音乐

       
    }


    /// <summary>
    /// 类型
    /// </summary>
    public enum EAudioType
    {
        Common,
        SFX,
        BGM,
        TK,
        Theme,
        All
    }


    public class AudioData
    {
        public EAudioType audioType = EAudioType.Common;
        public bool loop;
        public AudioSource AS { get; set; }
    }

    public class AudioOption
    {
        
    }

    public class IgnoreTime
    {
        public float value;
    }

}